#include "stdafx.h"
#include "CombinationGenerator.h"

using namespace System::Collections::Generic;
using namespace System::Linq;

namespace SpikingNeuronLib
{
	// static protected
	array<int>^ CombinationGenerator::InitializeCombinations(int groupSize)
	{
		array<int>^ combinations = gcnew array<int>(groupSize);

		for (int i = 0; i < groupSize; i++)
			combinations[i] = i;

		return combinations;
	}

	// static protected
	bool CombinationGenerator::GetNextCombinations(bool continueCombining, array<int>^ combinations, int groupSize, int numElementsToCombine)
	{
		// compute the next combination; exit if there are no more
		// note that combinations can overlap
		int i = 1;
		while (continueCombining && (++combinations[groupSize - i] > numElementsToCombine - i))
		{
			if (++i > groupSize)
			{
				continueCombining = false;		// exit outer while loop
			}
		}

		while (continueCombining && (i > 1))
		{
			combinations[groupSize - i + 1] = combinations[groupSize - i] + 1;
			i--;
		}

		return continueCombining;
	}

	// static public
	List<array<int>^>^ CombinationGenerator::GetCombinations(int groupSize, int numElementsToCombine)
	{
		array<int>^ combinations = InitializeCombinations(groupSize);
		List<array<int>^>^ results = gcnew List<array<int>^>();

		// loop until all combinations of size anchorCombinationGroupSize (typically triplets) have been explored
		bool testNextAnchorCombination = true;
		while (testNextAnchorCombination)
		{
			results->Add(Enumerable::ToArray<int>(combinations));
			testNextAnchorCombination = GetNextCombinations(testNextAnchorCombination, combinations, groupSize, numElementsToCombine);
		}

		return results;
	}

	CombinationGenerator::CombinationGenerator(int groupSize, int numElementsToCombine)
	{
		_groupSize = groupSize;
		_numElementsToCombine = numElementsToCombine;

		ReinitializeCombinations();
	}

	void CombinationGenerator::ReinitializeCombinations()
	{
		_combinations = InitializeCombinations(_groupSize);
	}

	bool CombinationGenerator::GetNextCombinations(bool continueCombining)
	{
		return GetNextCombinations(continueCombining, _combinations, _groupSize, _numElementsToCombine);
	}
}
